
#ifndef UM_FACTORY_H
#define UM_FACTORY_H

#include <map>

namespace UM {

struct DefaultFactoryErrorPolicy {
	template <class _Identifier>
	HRESULT onUnknownType(const _Identifier & id, void ** obj) {
		(id);
		(obj);
		return E_NOTIMPL;
	}
};

template <
	class _Product,
	class _Identifier, 
	class _Creator,
	class _ErrorPolicy = DefaultFactoryErrorPolicy>
class Factory : public _ErrorPolicy{

	typedef std::map<_Identifier, _Creator> _MapType;

public:

	typedef _Product    ProductType;
	typedef _Identifier IdentifierType;
	typedef _Creator    CreatorType;

	static HRESULT NewL(Factory ** obj) {
		*obj = 0;
		Factory * self = new Factory;
		if (self == 0) {
			return E_OUTOFMEMORY;
		}
		*obj = self;
		return S_OK;
	}

	HRESULT reg(const _Identifier & id, _Creator creator) {
		m_Cont[id] = creator;
		return S_OK;
	}

	HRESULT create(const _Identifier & id, std::auto_ptr<_Product> & obj) {
		_MapType::iterator it = m_Cont.find(id);
		if (it == m_Cont.end()) {
			return E_FAIL;
		}
		return (it->second)(obj);
	}

	template <class Param1>
	HRESULT create(const _Identifier & id, std::auto_ptr<_Product> & obj, Param1 p1) {
		_MapType::iterator it = m_Cont.find(id);
		if (it == m_Cont.end()) {
			return E_NOTIMPL;
		}
		return (it->second)(obj, p1);
	}

	template <class Param1, class Param2>
	HRESULT create(const _Identifier & id, std::auto_ptr<_Product> & obj, Param1 p1, Param2 p2) {
		_MapType::iterator it = m_Cont.find(id);
		if (it == m_Cont.end()) {
			return E_NOTIMPL;
		}
		return (it->second)(obj, p1, p2);
	}

private:

	_MapType	m_Cont;

};


} // namespace UM


using UM::Factory;


#endif // UM_FACTORY_H